Inside Macintosh: Sound

| Previous | Chapter contents | Chapter top | Section top | Next |

Manipulating a Sound That Is Playing

The Sound Manager provides a number of sound commands that you can use to change some of the characteristics of sounds that are currently playing. For example, you can alter the rate at which a sampled sound is played back, thereby lowering or increasing the pitch of the sound. You can also pause or stop a sound that is currently in progress. See "Pausing and Restarting Sound Channels" for information on how to pause the processing of a sound channel.

You can use the getRateCmd command to determine the rate at which a sampled sound is currently playing. If SndDoImmediate returns noErr when you pass getRateCmd , the current sample rate of the channel is returned as a Fixed value in the location that is pointed to by param2 of the sound command. (As usual, the high bit of that value returned is not interpreted as a sign bit.) Values that specify sampling rates are always interpreted relative to the 22 kHz rate. That is, the Fixed value $00010000 indicates a rate of 22 kHz. The value $00020000 indicates a rate of 44 kHz. The value $00008000 indicates a rate of 11 kHz.

To modify the pitch of a sampled sound currently playing, use the rateCmd command. The current pitch is set to the rate specified in the param2 field of the sound command. Listing 1-14 illustrates how to halve the frequency of a sampled sound that is already playing. Note that sending the rateCmd command before a sound plays has no effect.

Listing 14 Halving the frequency of a sampled sound

FUNCTION MyHalveFreq (mySndChan: SndChannelPtr): OSErr;
VAR
    myRate:         LongInt;                {rate of sound play}
    mySndCmd:       SndCommand;             {a sound command}
    myErr:          OSErr;
BEGIN
    {Get the rate of the sample currently playing.}
    mySndCmd.cmd := getRateCmd;             {the command is getRateCmd}
    mySndCmd.param1 := 0;                   {unused}
    mySndCmd.param2 := LongInt(@myRate);
    myErr := SndDoImmediate(mySndChan, mySndCmd);

    IF myErr = noErr THEN
    BEGIN
        {Halve the sample rate.}
        mySndCmd.cmd := rateCmd;            {the command is rateCmd}
        mySndCmd.param1 := 0;               {unused}
        mySndCmd.param2 := FixDiv(myRate, $00020000);
        myErr := SndDoImmediate(mySndChan, mySndCmd);
    END;
    MyHalveFreq := myErr;
END;

When you halve the frequency of a sampled sound using the technique in Listing 1-14 , the sound will play one octave lower than before. In addition, the sound will play twice as slowly as before. Likewise, if you use the rateCmd command to double the frequency of a sound, it plays one octave higher and twice as fast. Using rateCmd in this way is like pressing the fast forward button on a tape player while the play button remains depressed.

You can also use rateCmd and getRateCmd to pause a sampled sound that is currently playing. To do this, read the rate at which it is playing, issue a rateCmd command with a rate of 0, and then issue a rateCmd command with the previous rate when you want the sound to resume playing.

To change the amplitude (or loudness) of the sound in progress, issue the ampCmd command. (See Listing 1-15 for an example.) If no sound is currently playing, ampCmd sets the amplitude of the next sound. Specify the desired new amplitude in the param1 field of the sound command as a value in the range 0 to 255.

Listing 15 Changing the amplitude of a sound channel

PROCEDURE MySetAmplitude (chan: SndChannelPtr; myAmp: Integer);
VAR
    mySndCmd:       SndCommand;         {a sound command}
    myErr:          OSErr;
BEGIN
    IF chan <> NIL THEN
    BEGIN
        WITH mySndCmd DO
        BEGIN
            cmd := ampCmd;              {the command is ampCmd}
            param1 := myAmp;            {desired amplitude}
            param2 := 0;                {ignored}
        END;
        myErr := SndDoImmediate(chan, mySndCmd);
        IF myErr <> noErr THEN
            DoError(myErr);
    END;
END;

If your application has an option that allows users to turn off sound output, you could call the MySetAmplitude procedure on all open channels to set the amplitude of all channels to 0. Note that the Sound control panel allows the user to adjust the sound from 0 (softest) to 7 (loudest). This value is independent of the values used for amplitudes of sounds playing in channels, and the Sound Manager uses the Sound control panel value jointly with the amplitude of a sound channel to determine how loudly to play a sound. Sounds with low frequencies sound softer than sounds with high frequencies even if the sounds play at the same amplitude. If the amplitude of a sound is 0, the sound hardware produces no sound; however, when the value set in the Sound control panel is 0, sound might still play, depending on the amplitude.

You can use the getAmpCmd command to determine the current amplitude of a sound in progress. The getAmpCmd command is similar to getRateCmd , except that the value returned is an integer. The value returned in param2 is in the range 0-255. Listing 1-16 shows an example:

Listing 16 Getting the amplitude of a sound in progress

VAR
    myAmp:      Integer;
BEGIN
    mySndCmd.cmd := getAmpCmd;
    mySndCmd.param1 := 0;                                   {unused}
    mySndCmd.param2 := LongInt(@myAmp);
    myErr := SndDoImmediate(mySndChan, mySndCmd);
END;

To modify the timbre of a sound defined using by square-wave data, use the timbreCmd command. A sine wave is specified as 0 in param1 and produces a very clear sound. A value of 254 in param1 represents a modified square wave and produces a buzzing sound. To avoid a bug in some versions of the Sound Manager, you should not use the value 255. You should change the timbre before playing the sound.


© 1998 Apple Computer, Inc.

| Previous | Chapter contents | Chapter top | Section top | Next |